import { profanity } from '@2toad/profanity'
import { ConfigService } from '@nestjs/config'
import moment from 'moment'
import { Server } from 'socket.io'
import xss from 'xss'
import { IChatConfig, chatConfig } from '../../../config/chat'
import { User } from '../../models/User'
import { AppError } from '../../utils/AppError'
import { DanmakuFilter } from '../danmaku/DanmakuFilter'
import { RedisService } from '../redis/RedisService'
import { RoomStateService } from '../room/RoomStateService'

const config: IChatConfig = chatConfig

export class ChatService {
  constructor(
    private readonly io: Server,
    private readonly configService: ConfigService,
    private readonly redis: RedisService,
    private readonly roomState: RoomStateService,
    private readonly filter: DanmakuFilter
  ) {
    // 配置敏感词过滤
    profanity.addWords(chatConfig.room.filter.customWords)
    profanity.removeWords(chatConfig.room.filter.whitelistWords)
  }

  async sendMessage(data: {
    userId: string
    roomId: string
    content: string
    type?: 'text' | 'image' | 'gift' | 'system'
    color?: string
    meta?: any
  }) {
    const { userId, roomId, content, type = 'text', color, meta } = data

    // 检查用户权限
    await this.roomState.checkPermission(roomId, userId, 'chat')

    // 检查发送频率
    await this.checkSendFrequency(userId)

    // 内容过滤
    let filteredContent = content
    if (type === 'text') {
      // 消息长度限制
      if (content.length > chatConfig.room.limits.maxMessages) {
        throw new AppError(400, `消息过长，最大允许${chatConfig.room.limits.maxMessages}个字符`)
      }

      // XSS过滤
      filteredContent = xss(content, chatConfig.room.filter.xss)

      // 中文敏感词过滤
      filteredContent = await this.filter.process(filteredContent)
      if (!filteredContent) {
        throw new AppError(400, '消息包含敏感内容')
      }

      // 英文脏话过滤
      if (profanity.exists(filteredContent)) {
        throw new AppError(400, '消息包含不当内容')
      }

      // 中文表情符号处理
      filteredContent = filteredContent.replace(/[\uDE00-\uDE4F]/g, '')
    }

    // 创建消息对象
    const message = {
      id: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      userId,
      roomId,
      content: filteredContent,
      type,
      color: color || '#FFFFFF',
      meta,
      timestamp: Date.now(),
    }

    // 获取发送者信息
    const sender = await this.getUserInfo(userId)
    const fullMessage = { ...message, sender }

    // 广播消息
    this.io.to(roomId).emit('chat_message', fullMessage)

    // 保存消息记录
    await this.saveMessage(fullMessage)

    // 更新统计信息
    await this.updateStats(roomId, userId)

    return fullMessage
  }

  async getHistory(roomId: string, limit: number = 100) {
    const messages = await this.redis.lrange(`chat:history:${roomId}`, 0, limit - 1)
    return messages.map((msg) => JSON.parse(msg))
  }

  async clearHistory(roomId: string, userId: string) {
    await this.roomState.checkPermission(roomId, userId, 'clear_chat')
    await this.redis.del(`chat:history:${roomId}`)

    this.io.to(roomId).emit('chat_cleared', {
      roomId,
      clearedBy: userId,
      timestamp: Date.now(),
    })

    return true
  }

  private async checkSendFrequency(userId: string) {
    const key = `chat:frequency:${userId}`
    const count = await this.redis.incr(key)

    if (count === 1) {
      await this.redis.expire(key, chatConfig.room.frequency.interval)
    }

    if (count > chatConfig.room.frequency.maxMessages) {
      throw new AppError(429, '发送太频繁，请稍后再试')
    }
  }

  private async getUserInfo(userId: string) {
    const user = await User.findById(userId).select('nickname avatar level badges vipLevel')

    return {
      userId,
      nickname: user.nickname,
      avatar: user.avatar,
      level: user.level,
      badge: user.badges[0],
      vipLevel: user.vipLevel,
    }
  }

  private async saveMessage(message: any) {
    const key = `chat:history:${message.roomId}`
    await this.redis.lpush(key, JSON.stringify(message))
    await this.redis.ltrim(key, 0, chatConfig.room.history.maxLength - 1)
  }

  private async updateStats(roomId: string, userId: string) {
    const multi = this.redis.multi()

    // 更新房间消息数
    multi.hincrby(`room:${roomId}:stats`, 'messages', 1)
    multi.hincrby(`room:${roomId}:stats`, 'totalMessages', 1)

    // 更新用户消息数
    multi.hincrby(`user:${userId}:stats`, 'messages', 1)
    multi.hincrby(`user:${userId}:stats`, 'totalMessages', 1)

    // 更新日活跃度
    const today = moment().format('YYYY-MM-DD')
    multi.zincrby(`chat:active:${roomId}:${today}`, 1, userId)

    await multi.exec()
  }
}
